/*
 * Copyright (c) 2021 Huawei Device Co.,  Ltd.
 * Licensed under the Apache License,  Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,  software
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,  either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "cashdevice_service.h"
#include "devmgr.h"
#include "hilog_wrapper.h"
#include "cashdevice_status.h"

namespace SwanLink {
namespace Finance {

CashDeviceService::CashDeviceService():
    m_pFdHandler(new FdHandler()),
    m_pPlgMgr(new PluginManager()),
    m_iStatus(NOT_INIT)
{
}

CashDeviceService::~CashDeviceService()
{
    delete m_pFdHandler;
    delete m_pPlgMgr;
}

std::vector<DevAccess> CashDeviceService::GetSupportAccess()
{
    std::vector<DevAccess> result;
    char node[][MAX_DEV_NAME_LEN] = {"COM", "USB"};

    if (m_pPlgMgr == nullptr) {
        COMMON_HILOGE(COMMON_SRV, "Not init!");
        return result;
    }
    for (int i = 0; i < static_cast<int>(sizeof(node)/sizeof(node[0])); i++) {
        for (int k = 0; k < MAX_DEV_NUM; k++) {
            std::string name, dev;
            int mode;
            char com[MAX_DEV_NAME_LEN];
            snprintf(com, MAX_DEV_NAME_LEN, "%s%d", node[i], k+1);

            if (!DevMgr::GetDevConfig(com, name, dev, mode)) {
                m_iStatus = ERR_CONFIG_LOAD_FAILED;
                continue;
            }

            COMMON_HILOGD(COMMON_SRV, "get dev config success, name = %{public}s,dev = %{public}s,mode = %{public}d",
                    name.c_str(), dev.c_str(), (int)mode);
            DevAccess access;
            if (!m_pPlgMgr->GetAccess(name, (ACCESS_MODE)mode, dev, access)) {
                COMMON_HILOGW(COMMON_SRV, "get access failed,name = %{public}s,dev = %{public}s,mode = %{public}d",
                    name.c_str(), dev.c_str(), (int)mode);
                continue;
            }
            COMMON_HILOGD(COMMON_SRV,
                "get access success, name = %{public}s, desc = %{public}s, dev = %{public}s, mode = %{public}d",
                access.name, access.desc, access.transport.dev, access.transport.mode);

            result.push_back(access);
        }
    }
    return result;
}

int CashDeviceService::Open(const std::string& name, const Transport& tran)
{
    COMMON_HILOGD(COMMON_SRV, "Check Port %{public}s", tran.dev);
    if (m_pFdHandler->IsTakeUp(tran.dev)) {
        COMMON_HILOGD(COMMON_SRV, "Port is taken up");
        // 如果关闭了应重新打开
        int fd = m_pFdHandler->GetFd(tran.dev);
        std::shared_ptr<IAdaptor> adaptor = m_pFdHandler->GetAdaptor(fd);
        if (!adaptor->IsOpen()) {
            COMMON_HILOGD(COMMON_SRV, "Remove Adaptor from FdHandler");
            m_pFdHandler->DelFd(fd);
            m_iStatus = adaptor->Open(tran);
            if (m_iStatus != SUCCESS) {
                return m_iStatus;
            }
            return m_pFdHandler->AddFd(tran.dev, adaptor);
        }
        m_iStatus = SUCCESS;
        return fd;
    }

    COMMON_HILOGD(COMMON_SRV, "Create Adaptor");
    std::shared_ptr<IAdaptor> adaptor = m_pPlgMgr->CreateAdaptor(name);
    if (adaptor == nullptr)
        return m_pPlgMgr->GetStatus(name);

    COMMON_HILOGD(COMMON_SRV, "Open device %{public}s", tran.dev);
    m_iStatus = adaptor->Open(tran);
    if (m_iStatus != SUCCESS) {
        COMMON_HILOGD(COMMON_SRV, "Open failed, status = %{public}d", m_iStatus);
        return m_iStatus;
    }
    COMMON_HILOGD(COMMON_SRV, "Add Adaptor to FdHandler, nodev = %{public}s", tran.dev);
    return m_pFdHandler->AddFd(tran.dev, adaptor);
}

int CashDeviceService::Close(int handle)
{
    COMMON_HILOGD(COMMON_SRV, "Get Adaptor");
    std::shared_ptr<IAdaptor> adaptor = m_pFdHandler->GetAdaptor(handle);
    if (adaptor == nullptr) {
        COMMON_HILOGE(COMMON_SRV, "Handle invalid");
        m_iStatus = HANDLE_INVALID;
        return m_iStatus;
    }
    COMMON_HILOGD(COMMON_SRV, "Close device");
    m_iStatus = adaptor->Close();

    if (adaptor->IsOpen()) {
        return m_iStatus;
    }
    // 关闭的状态码
    COMMON_HILOGD(COMMON_SRV, "Remove Adaptor from FdHandler");
    m_pFdHandler->DelFd(handle);
    return m_iStatus;
}

int CashDeviceService::QueryStatus(int handle, int module, char *err)
{
    std::shared_ptr<IAdaptor> adaptor = m_pFdHandler->GetAdaptor(handle);
    if (adaptor == nullptr) {
        COMMON_HILOGE(COMMON_SRV, "Handle invalid");
        m_iStatus = HANDLE_INVALID;
        GetStatus(m_iStatus, err);
        return m_iStatus;
    }
    COMMON_HILOGD(COMMON_SRV, "Get Status");
    int status = adaptor->GetStatus(module, err);
    COMMON_HILOGD(COMMON_SRV, "Status = %{public}d", status);
    GetStatus(status, err);
    if (status != 0)
        return status;
    COMMON_HILOGD(COMMON_SRV, "Status = %{public}d", m_iStatus);
    GetStatus(m_iStatus, err);
    return m_iStatus;
}

int CashDeviceService::Reset(int handle)
{
    std::shared_ptr<IAdaptor> adaptor = m_pFdHandler->GetAdaptor(handle);
    if (adaptor == nullptr) {
        COMMON_HILOGE(COMMON_SRV, "Handle invalid");
        m_iStatus = HANDLE_INVALID;
        return m_iStatus;
    }
    m_iStatus = adaptor->Reset();
    return m_iStatus;
}

void CashDeviceService::OnInit(int devId, const std::string &attr)
{
    m_pFdHandler->SetBaseId(devId);
    m_pPlgMgr->LoadAllPlugin(attr);
}

void CashDeviceService::OnFree()
{
    m_pPlgMgr->FreeAllPlugin();
}

std::shared_ptr<IAdaptor> CashDeviceService::GetAdaptor(int handle)
{
    if (m_pFdHandler == nullptr) {
        COMMON_HILOGE(COMMON_SRV, "Not init");
        m_iStatus = NOT_INIT;
        return nullptr;
    }
    std::shared_ptr<IAdaptor> adaptor = m_pFdHandler->GetAdaptor(handle);
    if (adaptor == nullptr) {
        COMMON_HILOGE(COMMON_SRV, "Handle not found");
        m_iStatus = HANDLE_INVALID;
        return nullptr;
    }
    m_iStatus = SUCCESS;
    return adaptor;
}
}  // namespace Finance
}  // namespace SwanLink

